/*
Web: http://www.jsForms.com
Copyright (C) 2008  Igor Demyanov (mailto:Igor.Demyanov@gmail.com)
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
// ------------------------------------------------
// jsForms
// ------------------------------------------------
var jsForms = {
	Info:{
		Version:'0.5.4',
		Date:'07.11.2009'
	},
	IsDebug:false,
	Templates:{},
	ComponentCache:{},
	indexOf:function(value)
	{
		var len = this.length;
		for (var i = 0 ; i< len; i++)
		{
			if (this[i] == value)
			{
				return i;
			}
		}
		return -1;
	},
	swap:function(i1,i2)
	{
		var tmp = this[i1];
		this[i1] = this[i2];
		this[i2] = tmp;
	},
	ParseTemplate:function(template){
		var getAttributes = /\w+(=(("[^"]*")|('[^']*'))|)/g;
		var getAttrName = /\w*/;
		var fixSep1 = /\\"/g;
		var fixSep2 = /\\'/g;
		var refixSep1 = /\01/g;
		var refixSep2 = /\02/g;
	
		var zipSpace = / +/g;
		template = template.replace(fixSep1, String.fromCharCode(01)).replace(fixSep2, String.fromCharCode(02));
		var items = template.split(/</g);
		/*Node:
		 isRoot
		 isTag
		 isTextContent
		 isText
		 Text
		 isComponent
		 Type
		 isContent
		 InTo
		 
		 isProperties
		 isEvents
		 isKey
		 Name
		 Value
		 Type
		 Tag
		 
		 Name
		 Parent
		 Attributes:{}
		 Children:[]
		 */
		function parseAttributes(attrList){
			var tmp = {};
			for (var i = 1; i < attrList.length; i++) {
				var attrRAW = attrList[i];
				var len = attrRAW.indexOf('=');
				if (len == -1) {
					tmp[attrRAW] = {};
				}
				else {
					tmp[attrRAW.substring(0,len).toUpperCase()] = {
						value: attrRAW.substring(len+2, attrRAW.length - 1).replace(refixSep1, '\\"').replace(refixSep2, "\\'")
					}
				}
			}
			return tmp;
		}
	
		function createText(text){
			var tmp = new jsForms.Node();
			tmp.isText = true;
			tmp.Text = text;
			tmp.Attributes = attrList;
			return tmp;
		}
	
		function createTag(attrList){
			var tmp = new jsForms.Node();
			tmp.isTag = true;
			var tmpA = attrList["NAME"];
			if (tmpA) {
				tmp.Name = tmpA.value;
			}
			tmp.Attributes = attrList;
			return tmp;
		}
		//DEBUG
		//var logTab='';
		//DEBUG
	
		var root = new jsForms.Node();
		root.isRoot = true;
	
		var directAcces = {
			COMPONENT: function(){
				node = new jsForms.Node();
				node.isComponent = true;
				var tmpA = attrList["TYPE"];
				if (tmpA) {
					node.Type = tmpA.value;
				}
				var tmpA = attrList["NAME"];
				if (tmpA) {
					node.Name = tmpA.value;
				}
				node.Attributes = attrList;
			},
			PROPERTIES: function(){
				node = new jsForms.Node();
				node.isProperties = true;
			},
			EVENTS: function(){
				node = new jsForms.Node();
				node.isEvents = true;
			},
			CONTENT: function(){
				node = new jsForms.Node();
				node.isContent = true;
				var tmpA = attrList["INTO"];
				if (tmpA) {
					node.InTo = tmpA.value;
				}
			},
			KEY: function(){
				node = new jsForms.Node();
				node.isKey = true;
				var tmpA = attrList["NAME"];
				if (tmpA) {
					node.Name = tmpA.value;
				}
				var tmpA = attrList["VALUE"];
				if (tmpA) {
					node.Value = tmpA.value;
				}
				else {
					node.Value = tagExt;
				}
				var tmpA = attrList["TYPE"];
				if (tmpA) {
					node.Type = tmpA.value;
				}
				tagExt = undefined;
			}
		};
	
		var current = root;
		for (var i in items) {
			var item = items[i];
		
			if (item == '') {
				continue;
			}
		
			var fIndex = item.indexOf('>');
			if (fIndex == -1) {//Tag not completed?
				jsForms.error(item + ':Tag not completed');
			}
		
			var tagExt;
			if (fIndex + 1 == item.length) {
				tagExt = undefined;
			}
			else {
				tagExt = item.substring(fIndex + 1);
			}
			var tagInt = item.substring(0, fIndex);
		
			var attrList = tagInt.match(getAttributes);
			if (attrList == null) {
				jsForms.error(item + ':Tag not completed');
			}
		
			var tag = attrList[0].toUpperCase();
			var closeTagIndex = tagInt.lastIndexOf('/');// Save index
			if (closeTagIndex == 0) {//Close tag
				if (current.Tag != tag) {
					jsForms.error(item + ':Tag stack error, wait:"' + current.Tag + '",input:"' + tag + '"');
				}
				current = current.Parent;
			
				//DEBUG
				/*
				 logTab = logTab.substring(1);
				 jsForms.log(logTab+'</'+tag+'>');
				 */
				//DEBUG
			}
			else {
				attrList = parseAttributes(attrList);
				var node;
				var f = directAcces[tag];
				if (f)
				{
					f();
				}
				else {// Tag
					node = createTag(attrList);
				}
				node.Tag = tag;
				current.appendNode(node);
				//DEBUG
				//jsForms.log(logTab+node.NodeName);
				//DEBUG
			
				if (closeTagIndex != tagInt.length - 1) {
					current = node;
					//DEBUG
					//logTab =logTab+'\t';
					//DEBUG
				}
			}
		
			if (tagExt != undefined) {
				current.appendNode(createText(tagExt));
			}
		}
		return root;
	},
	CreateComponent:function(type,componentName,options)
	{
		//jsForms.log(type+'.Create');
		if (!jsForms.ComponentCache[type]) {
			jsForms.log(type + '.Compilation');
			var time = new Date().valueOf();// DEBUG - start;
			jsForms.CreateCache(type,options);
			time = new Date().valueOf() - time;// DEBUG - start;
			jsForms.ComponentCache[type].DebugInfo.CompilationTime = time;
			var time = new Date().valueOf();// DEBUG - start;
			var obj = jsForms.ComponentCache[type].Create(componentName);
			time = new Date().valueOf() - time;// DEBUG - start;
			jsForms.ComponentCache[type].DebugInfo.CreateTime= time;
			return obj;
		}
	
		return jsForms.ComponentCache[type].Create(componentName);
	},
	CleanCache:function (type)
	{
		if (jsForms.ComponentCache[type])
		{
			delete (jsForms.ComponentCache[type]);
		}
	}
};

if ($.browser.msie)
{
	jsForms.IsCompatibilityMode = true;
}else
if ($.browser.mozilla && $.browser.version.substr(0,3)=="1.8")//FF2
{
	jsForms.IsCompatibilityMode = true;
}


if (jsForms.IsDebug == true) {
	jsForms.log = function(text){console.log(text);};
	jsForms.error = function(text){console.error(text);debugger;throw text;};
}
else
{
	jsForms.log = function(){};
	jsForms.error = function(text){ throw text;};
}

jsForms.Node = function(){
	this.Children=[];
	this.Attributes={};
};
jsForms.Node.prototype={
	appendNode:function(node)
	{
		var old = node.Parent;
		if (old)
		{
			old.removeNode(node);
		}
		this.Children.push(node);
		node.Parent = this;
	},
	removeNode:function(node)
	{
		if (node.Parent != this)
		{
			return;
		}
		node.Parent = undefined;
		if (!this.Children.indexOf)
		{
			this.Children.indexOf = jsForms.indexOf;
		}
		var index = this.Children.indexOf(node);
		if (index != -1) {
			this.Children.splice(index,1);
		}
	}
}


jsForms.CreateCache_CreateVisual = function(type,dom,options)
{
	if (!jsForms.Templates[type])
	{
		jsForms.error('Not found "'+type+'" Component!');
	}
	
	var tmp = jsForms.ParseTemplate(jsForms.Templates[type],options);
	var isDesign = options && options.Design == true;
	
	if (tmp.Children.length != 1)
	{
		jsForms.error('Only one root element!');
	}
	
	// Optimization 
	dom.push('var doc=document;var mvc=jsForms;var cacheT=mvc.ComponentCache["'+type+'"];');
	
	function createElement(de,num)
	{
		dom.push('var el'+num+'=doc.createElement("'+de.Tag+'");');
		if (de.Attributes["CLASS"]) {
			dom.push('el' + num + '.className="' + de.Attributes["CLASS"].value + '";');
		}
		if (de.Attributes["ID"]) {
			dom.push('el' + num + '.id="' + de.Attributes["ID"].value + '";');
		}
		//debugger;
		for(var i in de.Attributes)
		{
			var attr = de.Attributes[i];
			if (i!='ID' && i!='CLASS') {
				dom.push('el'+num+'.setAttribute("'+i+'","'+attr.value+'");');
				//jsForms.log(i + ':' + attr.value);
			}
			if (i =="NAME" && RootIsDefine)
			{
				dom.push('o.C["'+attr.value+'"]=$(el'+num+');');
			}
		}
	};
	function createTextElement(de,num)
	{
		var sText = de.Text.replace(/"/g,'\\"').replace(/'/g,"\\'").replace(/\n/g,"\\n");
		dom.push('var el'+num+'=doc.createTextNode("'+sText+'");');
	}

	function createContent(comp)
	{
		var contents = comp.Children;
		var compType = comp.Type;
		for (var i = 0; i < contents.length; i++) {
			var item = contents[i];
			if (item.isContent != true)
			{
				continue;
			}
			var into = item.InTo;
			if (into == undefined || into == null) {
				into = 'content';
			}
			if (!jsForms.CheckContent(compType,into))
			{
				jsForms.error(compType+':'+into+' - Content not found');
				continue;
			}
			if (into == "object"){
				dom.push('var el' + count + '=newObj[0];');
			}else{
				dom.push('var el' + count + '=newObj.C["' + into + '"][0];');
			}
			jobList.push({
				skip: true
			});
		
			var items = item.Children;
			for (var ii = 0; ii < items.length; ii++) {
				jobList.push({
					p: count,
					e: items[ii]
				});
			}
			count+=items.length+1;
		}
	};
	
	/*Node:
	 	isRoot
	 	isTag
		 	Tag
	 	isText
		 	Text
	 	isComponent
	 	isContent
	 		InTo
		
		isProperties
		isEvents
		isKey
			Name
			Value
		
		Name
	 	Parent
	 	Attributes:{}
	 	Children:[]
	 */
	
	var RootIsDefine = false;
	var jobList = [{e:tmp.Children[0]}];
	if (isDesign)
	{
		options.DesignRoot =  tmp;
		options.DesignArray = jobList;
	}
	var index = 0;
	var count = 1;
	while (index < count)
	{
		var elem = jobList[index];
		if (elem.skip)
		{
			index++;
			continue;
		}

		if (elem.e.isText == true) {//Text
			createTextElement(elem.e, index);
		}
		else {// Component or Tag?
			if (elem.e.isComponent != true) {
				createElement(elem.e, index);
				
				for (var i = 0; i < elem.e.Children.length; i++) {
					jobList.push({
						p: index,
						e: elem.e.Children[i]
					});
				}
				count += elem.e.Children.length;
			}
			else {
				jsForms.CreateCache_IncludeComponent(elem.e, dom, type, index);
				dom.push('var el' + index + '=newObj[0];');
				if (isDesign) {
					dom.push('var ob' + index + '=newObj;');
				}
				createContent(elem.e);
			}
		}
		if (elem.p== undefined)
		{
			dom.push('var o=$(el'+index+');');
			dom.push('el'+index+'._OBJ=o;');
			dom.push('o.C={};o.E={};o.P={};');
			dom.push('o.Components=o.C;o.Events=o.E;o.Properties=o.P;');
			//dom.push('el'+index+'.setAttribute("ctype","'+type+'");');
			dom.push('if(compName){');
			dom.push('el'+index+'.setAttribute("name",compName);');
			dom.push('o._Name=compName;}o._Type="'+type+'";');
			jsForms.CreateCache_CopyFunction(type,dom);
			RootIsDefine = true;
		}
		else
		{
			dom.push('el'+elem.p+'.appendChild(el'+index+');');
		}
		index++;
	}
};

jsForms.CreateCache_CopyFunction = function(type,initFunctionArr)
{
	initFunctionArr.push('var s=mvc.Components.Component;');
	for(var i in jsForms.Components.Component)
	{
		initFunctionArr.push('o.'+i+'=s.'+i+';');
	};
	initFunctionArr.push('var s=mvc.Components["'+type+'"];');
	for(var i in jsForms.Components[type])
	{
		if (i != "_CompileInfo") {
			initFunctionArr.push('o.' + i + '=s.' + i + ';');
		}
	};
};
jsForms.CreateCache_InitProperties = function(comp,initFunctionArr,type,compType,compName)
{
	var items = [];
	var itemsC = comp.Children;
	for (var i = 0; i < itemsC.length; i++) {
		if (itemsC[i].isProperties== true)
		{
			var itemsCK = itemsC[i].Children;
			for (var i = 0; i < itemsCK.length; i++) {
				if (itemsCK[i].isKey == true)
				items.push(itemsCK[i]);
			}
		}
	}
	for (var i=0; i < items.length ; i++)
	{
		var key = items[i];
		var keyName = key.Name;
		var keyValue = key.Value;
		var keyType = key.Type;
		try
		{
			if (key.Attributes['DISABLE']!= undefined)
			{
				continue;
			}

			//jsForms.log(compName+':InitProperties(name="'+keyName+'",value="'+keyValue+'",type="'+keyType+'")');
			var propertyInfo = jsForms.GetPropertyInfo(compType,keyName);
			if (!propertyInfo)
			{
				jsForms.error(compName+':'+compType+':"'+keyName+'" - Property not found');
				continue;
			}
			
			if (keyType == undefined || keyType == null)
			{
				keyType = propertyInfo.Type;
			}
			else
			{
				keyType = keyType.toUpperCase();
			}
			
			switch (keyType) {
			case 'OBJECT':
				jsForms.ComponentCache[type].Constants[compName+'_'+keyName] = eval('('+keyValue+')');
				keyValue = 'mvc.Clone(cacheT.Constants["'+compName+'_'+keyName+'"])';
				break;
			default:
				keyValue="'"+keyValue.replace(/"/g,'\\"').replace(/'/g,"\\'")+"'";
				break;
			}
			
			if (propertyInfo.isDirect == true)
			{
				initFunctionArr.push('newObj.P.'+keyName+'='+keyValue+';');
			}
			else
			if (propertyInfo.isSetter == true)
			{
				initFunctionArr.push('newObj.Set'+keyName+'('+keyValue+');');
			}
			else
			{
				jsForms.error(compName+':'+compType+':"'+keyName+'" - setter not defined');
				continue;
			}
		}
		catch(e)
		{
			jsForms.error(compName+':'+compType+':InitProperties(name="'+keyName+'",value="'+keyValue+'",type="'+keyType+'"):\n'+e);
		}
	}
};

jsForms.CreateCache_InitEvents= function (comp,initFunctionArr,type,compType,compName)
{
	var items = [];
	var itemsC = comp.Children;
	for (var i = 0; i < itemsC.length; i++) {
		if (itemsC[i].isEvents== true)
		{
			var itemsCK = itemsC[i].Children;
			for (var i = 0; i < itemsCK.length; i++) {
				if (itemsCK[i].isKey == true)
				items.push(itemsCK[i]);
			}
		}
	}
	for (var i=0; i < items.length ; i++)
	{
		var key = items[i];
		var keyName = key.Name;
		var keyValue = key.Value;
		if (jsForms.Components[type][keyValue])
		{
			if (!jsForms.CheckEvent(compType,keyName))
			{
				jsForms.error(compName+':'+compType+':"'+keyName+'" - Event not found');
				continue;
			}
			initFunctionArr.push('newObj.E.'+keyName+'={obj:o, func: o[\''+keyValue+'\']};');
			//targetObj.Events[keyName] = {obj: parentObj, func:parentObj[keyValue]};
		}else
		{
			jsForms.error(compName+':'+compType+':InitEvents(name="'+keyName+'",value="'+type+'.'+keyValue+'")');
		}
	}
};

jsForms.CreateCache_IncludeComponent = function(comp,initFunctionArr,type,index)
{
		//debugger;
		var compType = comp.Type;
		var compName = comp.Name;
		var compClass;
		if (comp.Attributes['CLASS'])
		{
			compClass = comp.Attributes['CLASS'].value;
		}
		//var autoName = false;
		if (compType==undefined)
		{
			jsForms.error(type+':Component type undefined!');
		}
		if (compName == undefined)
		{
		//	autoName = true;
			compName = '_C'+index;
			jsForms.log(type+':Component name undefined, auto generate name:"'+compName+'"');
			//jsForms.error('Component name undefined!');
			//throw 'Component name undefined!';
		}
		
		initFunctionArr.push('var newObj=mvc.CreateComponent("'+compType+'","'+compName+'");');
		if (compClass!=undefined)
		{
			initFunctionArr.push('newObj[0].className=newObj[0].className+" '+compClass+'";');
		}

		initFunctionArr.push('o.C.' + compName + ' = newObj;');
		
		jsForms.CreateCache_InitProperties(comp,initFunctionArr,type,compType,compName);
		jsForms.CreateCache_InitEvents(comp,initFunctionArr,type,compType,compName);
};


jsForms.CreateCache = function(type,options)
{
	var initFunctionArr = ['jsForms.ComponentCache["'+type+'"].Create = function(compName){'];

	jsForms.ComponentCache[type] = {
		Constants:{},
		DebugInfo:{}
	}
	//if (options && options.VisualMethod) {
	//	options.VisualMethod(type, initFunctionArr, options);
	//}
	//else {
	jsForms.CreateCache_CreateVisual(type, initFunctionArr, options);
	//}

	initFunctionArr.push('return o;');
	initFunctionArr.push('}');
	if (jsForms.IsDebug == true) {
		jsForms.log('--------- ' + type + ' ------------');
		jsForms.log(initFunctionArr.join('\n'));
		jsForms.log('-------------------------------');
	}
	
	eval(initFunctionArr.join(''));
};
jsForms.Clone = function(targetObj)
{
	switch(typeof(targetObj))
	{
		case 'function': return targetObj;
		case 'object':{
			var newObj = {};
			for(var i in targetObj)
			{
				newObj[i] = targetObj[i];
			}
			return newObj;
		}
		default: return targetObj;
	}
};

jsForms.CopyFunction = function(target,source)
{
	for(var i in jsForms.Components.Component)
	{
		target[i] = jsForms.Components.Component[i];
	};
	if (source)
	{
		for(var i in source)
		{
			target[i] = source[i];
		}
	};
	return target;
};

jsForms.CreateCompileInfo = function(type,category,infoName,infoSetting)
{
	var component = jsForms.Components[type];
	if (!component)
	{
		var s='Component "'+type+'" not found!';
		jsForms.error(s);
		throw s;
	};
	
	if (!component._CompileInfo)
	{
		component._CompileInfo = {
		};
	};
	var c = component._CompileInfo;
	if (!c[category])
	{
		c[category]={};
	};
	if (!infoSetting)
	{
		var s='Component "'+type+'", compile info not set!';
		jsForms.error(s);
		throw s;
	}
	c[category][infoName] = infoSetting;
};

jsForms.GetCompileInfo = function(type,category,infoName)
{
	var component = jsForms.Components[type];
	if (!component)
	{
		var s='Component "'+type+'" not found!';
		jsForms.error(s);
		throw s;
	};
	var c = component._CompileInfo;
	if(!c ||!c[category])
	{
		return;
	}
	var c =c[category][infoName];
	if (!c) {
		return;
	}
	else {
		return c;
	}
};

jsForms.CheckCompileInfo = function(type,category,infoName)
{
	var component = jsForms.Components[type];
	if (!component)
	{
		var s='Component "'+type+'" not found!';
		jsForms.error(s);
		throw s;
	};
	var c = component._CompileInfo;
	if(!c)
	{
		/*var s='CompileInfo for "'+type+'" not defined!';
		jsForms.error(s);
		throw s;*/
		return false;
	}
	if (!c[category])
	{
		/*var s='CompileInfo.'+category+' for "'+type+'" not defined!';
		jsForms.error(s);
		throw s;*/
		return false;
	}
	var c =c[category][infoName];
	if (!c) {
		return false;
	}
	else {
		return true;
	}
//	
};

jsForms.CheckContent = function(type,contentName)
{
	return jsForms.CheckCompileInfo(type,"Contents",contentName);
};
jsForms.CheckEvent = function(type,eventName)
{
	return jsForms.CheckCompileInfo(type,"Events",eventName);
};
jsForms.CheckProperty = function(type,propertyName)
{
	return jsForms.CheckCompileInfo(type,"Properties",propertyName);
};
jsForms.GetPropertyInfo = function(type,propertyName)
{
	return jsForms.GetCompileInfo(type,"Properties",propertyName);
};

jsForms.CreateProperty = function(componentName,propertyName,propertySetting)
{
	/*
	 <PropertyName1>:{ Type:<PropertyType><,Values:{object}>, Access:<PropertyAccess>,Description:<String>}
	  PropertyType in ('Boolean','String','Object','Int','Float','Values',<undefined>) <undefined> - is default
	 PropertyAccess in ('Direct','Set','Get','GetSet') 'GetSet' - is default
	 */
	var sE;
	if (componentName == undefined || componentName == '')
	{
		sE = 'Component name not set';
		jsForms.error(sE);
		throw sE;
	}
	
	if (!propertyName){
		sE = componentName+':Property name - not set';
		jsForms.error(sE);
		throw sE;
	}
	propertySetting.Name = propertyName;
	propertySetting.isProperty = true;
	if (!propertySetting) {
		sE = componentName+':'+propertyName+':Property setting - not set';
		jsForms.error(sE);
		throw sE;
	}
	if (!propertySetting.Type)
	{
		sE = componentName+':'+propertyName+':Type - not set, Type = "undefined"';
		jsForms.log(sE);
		propertySetting.Type="undefined";
	}
	propertySetting.Type = propertySetting.Type.toUpperCase();
	switch (propertySetting.Type)
	{
			case "UNDEFINED":
			case "OBJECT":
			case "BOOLEAN":
			case "INT":
			case "FLOAT":
			case "STRING":
			break;
		case "VALUES":
		 if (!propertySetting.Values)
		 {
		 	sE=componentName+':'+propertyName+':'+propertySetting.Type+'": values list undefined!';
			jsForms.error(s);
			throw s;
		 }
		break;
		default:
		{
			sE=componentName+':'+propertyName+': uncorrect type "'+propertySetting.Type+'", using: "UNDEFINED"'+
			', "OBJECT", "BOOLEAN", "INT", "FLOAT", "STRING", "VALUES"';
			jsForms.error(sE);
			throw sE;
		}
	}
	if (!propertySetting.Access)
	{
		sE = componentName+':'+propertyName+':Access - not set, Access = "GetSet"';
		jsForms.log(sE);
		propertySetting.Access="GetSet";
	}
	propertySetting.Access = propertySetting.Access.toUpperCase();
	if (propertySetting.Access == "SETGET")
	{
		propertySetting.Access = "GETSET";
	}
	switch (propertySetting.Access) {
		case "DIRECT":
			propertySetting.isDirect = true;
			break;
		case "SET":
		case "GETSET":
			propertySetting.isSetter = true;
			break;
		case "GET":
			break;
		default:
		{
			sE=componentName+':'+propertyName+': uncorrect access "'+propertySetting.Access+'"';
			jsForms.error(sE);
			throw sE;
		}
	}
	
	jsForms.CreateCompileInfo(componentName,"Properties",propertyName,propertySetting);
};
jsForms.CreateContent = function(componentName,contentName,contentSetting)
{
	var sE;
	if (componentName == undefined || componentName == '')
	{
		sE = 'Component name not set';
		jsForms.error(sE);
		throw sE;
	}
	if (!contentName){
		sE = componentName+':Content name - not set';
		jsForms.error(sE);
		throw sE;
	}
	if (!contentSetting) {
		sE = componentName+':'+contentName+':Content setting - not set';
		jsForms.error(sE);
		throw sE;
	}
	jsForms.CreateCompileInfo(componentName,"Contents",contentName,contentSetting);
}
jsForms.CreateEvent = function(componentName,eventName,eventSetting)
{
	var sE;
	if (componentName == undefined || componentName == '')
	{
		sE = 'Component name not set';
		jsForms.error(sE);
		throw sE;
	}
	if (!eventName){
		sE = componentName+':Event name - not set';
		jsForms.error(sE);
		throw sE;
	}
	if (!eventSetting) {
		sE = componentName+':'+eventName+':Event setting - not set';
		jsForms.error(sE);
		throw sE;
	}
	eventSetting.Name = eventName;
	eventSetting.isEvent = true;
	jsForms.CreateCompileInfo(componentName,"Events",eventName,eventSetting);
};

/*
 PropertyType in ('Boolean','String','Object','Int','Float','Values',<undefined>) <undefined> - is default
 PropertyAccess in ('Direct','Set','Get','GetSet') 'GetSet' - is default
 
 {Name:<ComponentType>,
	Properties:{// Property list
	 	<PropertyName1>:{ Type:<PropertyType><,Values:{object}>, Access:<PropertyAccess>,Description:<String>},
	 	<PropertyName2>:{ Type:<PropertyType>,Access:<PropertyAccess>},
	 	e.t.c
 		}
	 Events:{
	 	<EventName1>:{Description:<String>},
	 	<EventName2>:{Description:<String>},
	 	<EventName3>:{Description:<String>},
	 	e.t.c},
	 Contents:
	 {
	 	<ContentName1>:{Description:<String>},
	 	<ContentName2>:{Description:<String>},
	 	<ContentName3>:{Description:<String>},
 		e.t.c}
 }
 */
jsForms.CreateCompileInfoByObject = function(o)
{
	var sE;
	if (!o){
		sE = 'Object info is null';
		jsForms.error(sE);
		throw sE;
	}
	if (o.Name == undefined || o.Name == '')
	{
		sE = 'Component name not set';
		jsForms.error(sE);
		throw sE;
	}
	if (o.Properties)
	{
		for (var i in o.Properties)
		{
			jsForms.CreateProperty(o.Name,i,o.Properties[i]);
		}
	}
	if (o.Events)
	{
		for (var i in o.Events)
		{
			jsForms.CreateEvent(o.Name,i,o.Events[i]);
		}
	}
	if (o.Contents)
	{
		for (var i in o.Contents)
		{
			jsForms.CreateContent(o.Name,i,o.Contents[i]);
		}
	}
};

jsForms.GetObject=function(element)
{
	return element._OBJ;
}

jsForms.GetObjectByType = function(el,foundType){
	if (!el) 
		return;
	do {
		var obj = jsForms.GetObject(el);
		if (obj) {
			if (obj._Type == foundType) {
				return obj;
			}
		}
		el = el.parentNode;
	}
	while (el);
}

// ------------------------------------------------
// Component
// ------------------------------------------------
jsForms.Components = {
	Component: {
		// jQuery fix
		append:function(v)
		{
			jQuery.fn.append.call(this,v);
			return this;
		},
		appendTo:function(v)
		{
			jQuery.fn.appendTo.call(this,v);
			return this;
		},
		Init: function(){
			for (var i in this.C) {
				if (this.C[i].Init) {
					this.C[i].Init();
				}
			}
			return this;
		},
		_GetProperty: function(name){
			return this.P[name];
		},
		_SetProperty: function(name, value){
			this.P[name] = value;
			return this;
		},
		_SetEvent: function(name,obj,func)
		{
			if (func) {
				this.E[name] = {
					obj: obj,
					func: func
				};
			}else
			{
				this.E[name] = undefined;
			}
			return this;
		},
		_GetEvent:function(name)
		{
			return this.E[name];
		},
		_ExecEvent:function(name,arguments)
		{
			if (this.E[name])
			{
				this.E[name].func.call(this.E[name].obj,arguments);
			}
			return this;
		},
		_AddComponent:function(component,name)
		{
			if (name == undefined)
			{
				name=new Date().valueOf();
			}
			component._Name = name;
			this.C[name]= component;
			return this;
		},
		_RemoveComponent:function(value)
		{
			if (typeof(value)!='string')//not name
			{
				value = value._Name;
			}
			delete this.C[value];
			return this;
		}
	}
};

